home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue35 / eval_dan / EVAL_DAN.ZIP / Mathcomp.pas < prev    next >
Pascal/Delphi Source File  |  1997-12-30  |  44KB  |  1,595 lines

  1. unit mathcomp;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
  7.  
  8. type
  9.   TVector2D = record
  10.     x,y: double;
  11.   end;
  12.  
  13.   TVector3D = record
  14.     X,Y,Z: Double;
  15.   end;
  16.  
  17.   TTokenType = (ttUnknown,ttOperation,ttVariable,ttConstant);
  18.  
  19.   //TVariableList
  20.   PVariableRecord = ^TVariableRecord;
  21.   TVariableRecord = record
  22.     VarData: Double;
  23.     VarName: String;
  24.   end;
  25.  
  26.   //Forward declarations
  27.   TExpressionTree = class;
  28.  
  29.   TVarList = class(TList)
  30.   private
  31.     function GetVars(Index: String): PVariableRecord;
  32.   public
  33.     property Vars[Index: String]: PVariableRecord read GetVars;
  34.     //Methods
  35.     destructor Destroy; override;
  36.     function GetIndex(AValue: String): Integer;
  37.     function NewVar(AName: String; AData: Double): PVariableRecord;
  38.   end;
  39.  
  40.   TExpressionNode = class(TObject)
  41.   private
  42.     FValue: String;
  43.     FParent: TExpressionNode;
  44.     FTokenType: TTokenType;
  45.     FChildren: TList;
  46.     FValidValue: Boolean;
  47.     FNumValue: Double;
  48.     FVarPointer: PVariableRecord;
  49.     FTree: TExpressionTree;
  50.   public
  51.     property Value: String read FValue write FValue;
  52.     property Parent: TExpressionNode read FParent write FParent;
  53.     property TokenType: TTokenType read FTokenType write FTokenType;
  54.     property Children: TList read FChildren write FChildren;
  55.     property ValidValue: Boolean read FValidValue write FValidValue;
  56.     property NumValue: Double read FNumValue write FNumValue;
  57.     property VarPointer: PVariableRecord read FVarPointer write FVarPointer;
  58.     property Tree: TExpressionTree read FTree write FTree;
  59.     //Methods
  60.     function CreateChild: TExpressionNode;
  61.     function Evaluate(SuppressErrors,UseVars: Boolean): Double;
  62.     constructor Create(AOwner: TExpressionNode; ATree: TExpressionTree);
  63.     destructor Destroy; override;
  64.   end;
  65.  
  66.   TExpressionTree = class(TPersistent)
  67.   private
  68.     FTopNode: TExpressionNode;
  69.     FExpression: String;
  70.     FCheckSyntax: Boolean;
  71.     FTokens: TStringList;
  72.     FVarList: TVarList;
  73.     procedure SetExpression(AValue: String);
  74.   public
  75.     property TopNode: TExpressionNode read FTopNode write FTopNode;
  76.     property Expression: String read FExpression write SetExpression;
  77.     property CheckSyntax: Boolean read FCheckSyntax write FCheckSyntax;
  78.     property Tokens: TStringList read FTokens write FTokens;
  79.     property VarList: TVarList read FVarList write FVarList;
  80.     //Methods
  81.     constructor Create;
  82.     destructor Destroy; override;
  83.     procedure MakeTokens;
  84.     procedure RemoveBadTokens;
  85.   end;
  86.  
  87.   TDataSet2D = class(TObject)
  88.   private
  89.     FData: pointer;
  90.     FCount: Longint;
  91.     function GetData(Index: Longint): TVector2D;
  92.     procedure SetData(Index: Longint; AValue: TVector2D);
  93.     procedure SetCount(AValue: longint);
  94.   public
  95.     property Data[Index: longint]: TVector2D read GetData write SetData;
  96.     property Count: longint read FCount write SetCount;
  97.     constructor Create(ACount: Longint);
  98.     destructor Destroy; override;
  99.   end;
  100.  
  101.   TDataSet3D = class(TObject)
  102.   private
  103.     FData: pointer;
  104.     FCount: Longint;
  105.     function GetData(Index: Longint): TVector3D;
  106.     procedure SetData(Index: Longint; AValue: TVector3D);
  107.     procedure SetCount(AValue: longint);
  108.   public
  109.     property Data[Index: longint]: TVector3D read GetData write SetData;
  110.     property Count: longint read FCount write SetCount;
  111.     constructor Create(ACount: Longint);
  112.     destructor Destroy; override;
  113.   end;
  114.  
  115.   TDataLabel = class(TObject)
  116.   private
  117.     FData: String;
  118.     Fx,Fy: integer;
  119.   public
  120.     property Data: string read FData write FData;
  121.     property x: integer read Fx write Fx;
  122.     property y: integer read Fy write Fy;
  123.   end;
  124.  
  125.   {TAxesView}
  126.  
  127.   TAxesAlign = (aaPositive,aaNegative);
  128.   TCoord2DFunc = function (InV: TVector2D): TVector2D of Object;
  129.   TCoord3DFunc = function (InV: TVector3D): TVector3D of Object;
  130.  
  131.   TAxesView = class(TCustomControl)
  132.   private
  133.     { Private declarations }
  134.     FXMin,FXMax,FXScale,FYMin,FYMax,FYScale: double;
  135.     FShowGrid,FShowAxes,FShowLabels,FAutoUpdate: Boolean;
  136.     FXAxisColor,FYAxisColor,FGridColor: TColor;
  137.     FOnGetMathCoord,FOnGetRealCoord: TCoord2DFunc;
  138.     FRXScale,FRYScale: Double;
  139.     FOrigin: TVector2D;
  140.     FGrid: TDataSet2D;
  141.     FLabels: TList;
  142.     FDecimals: Integer;
  143.     FAlignLabelX,FAlignLabelY: TAxesAlign;
  144.     FOnPaint: TNotifyEvent;
  145.     procedure SetXMin(AValue: Double);
  146.     procedure SetXMax(AValue: Double);
  147.     procedure SetXScale(AValue: Double);
  148.     procedure SetYMin(AValue: Double);
  149.     procedure SetYMax(AValue: Double);
  150.     procedure SetYScale(AValue: Double);
  151.     procedure SetShowGrid(AValue: Boolean);
  152.     procedure SetShowAxes(AValue: Boolean);
  153.     procedure SetShowLabels(AValue: Boolean);
  154.     procedure SetXAxisColor(AValue: TColor);
  155.     procedure SetYAxisColor(AValue: TColor);
  156.     procedure SetGridColor(AValue: TColor);
  157.     procedure SetAlignLabelX(AValue: TAxesAlign);
  158.     procedure SetAlignLabelY(AValue: TAxesAlign);
  159.     procedure SetDecimals(AValue: Integer);
  160.     procedure FontChange(Sender: TObject); virtual;
  161.     //inherited methods
  162.   protected
  163.     { Protected declarations }
  164.     procedure DrawAxes; virtual;
  165.     procedure DrawGrid; virtual;
  166.     procedure DrawLabels; virtual;
  167.   public
  168.     { Public declarations }
  169.     property Labels: TList read FLabels write FLabels;
  170.     property RXScale: double read FRXScale;
  171.     property RYScale: double read FRYScale;
  172.     property Origin: TVector2D read FOrigin;
  173.     property Grid: TDataSet2D read FGrid;
  174.     //Methods
  175.     procedure DoAutoPan(X,Y: Integer); virtual;
  176.     procedure Zoom(Percent: Integer);
  177.     procedure SetScale(AXMin,AXMax,AXScale,AYMin,AYMax,AYScale: Double);
  178.     function GetMathCoord(InV: TVector2D): TVector2D; virtual;
  179.     function GetRealCoord(InV: TVector2D): TVector2D; virtual;
  180.     procedure RecalcScale; virtual;
  181.     constructor Create(AOwner: TComponent); override;
  182.     destructor Destroy; override;
  183.     procedure Paint; override;
  184.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  185.   published
  186.     { Published declarations }
  187.     property AutoUpdate: Boolean read FAutoUpdate write FAutoUpdate;
  188.     property AlignLabelX: TAxesAlign read FAlignLabelX write SetAlignLabelX;
  189.     property AlignLabelY: TAxesAlign read FAlignLabelY write SetAlignLabelY;
  190.     property XMin: double read FXMin write SetXMin;
  191.     property XMax: double read FXMax write SetXMax;
  192.     property XScale: double read FXScale write SetXScale;
  193.     property YMin: double read FYMin write SetYMin;
  194.     property YMax: double read FYMax write SetYMax;
  195.     property YScale: double read FYScale write SetYScale;
  196.     property ShowGrid: Boolean read FShowGrid write SetShowGrid;
  197.     property ShowAxes: Boolean read FShowAxes write SetShowAxes;
  198.     property ShowLabels: Boolean read FShowLabels write SetShowLabels;
  199.     property XAxisColor: TColor read FXAxisColor write SetXAxisColor;
  200.     property YAxisColor: TColor read FYAxisColor write SetYAxisColor;
  201.     property GridColor: TColor read FGridColor write SetGridColor;
  202.     property Decimals: Integer read FDecimals write SetDecimals;
  203.     //Inherited properties to be published
  204.     property Color;
  205.     property Font;
  206.     property Align;
  207.     //Events
  208.     property OnGetMathCoord: TCoord2DFunc read FOnGetMathCoord write FOnGetMathCoord;
  209.     property OnGetRealCoord: TCoord2DFunc read FOnGetRealCoord write FOnGetRealCoord;
  210.     property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
  211.     //Inherited events to be published
  212.     property OnEnter;
  213.     property OnExit;
  214.     property OnDblClick;
  215.     property OnDragDrop;
  216.     property OnDragOver;
  217.     property OnEndDrag;
  218.     property OnMouseDown;
  219.     property OnMouseMove;
  220.     property OnMouseUp;
  221.     property OnStartDrag;
  222.   end;
  223.  
  224. const
  225.   ValidOps = ['+','-','*','/',')','(','^','='];
  226.  
  227. procedure Register;
  228. function V2D(x,y: double): TVector2D;
  229. function V3D(vx,vy,vz: double): TVector3D;
  230. function V2D2Point(V: TVector2D): TPoint;
  231. function V3DXY(V: TVector3D): TVector2D;
  232. function V3DXZ(V: TVector3D): TVector2D;
  233. function V3DZY(V: TVector3D): TVector2D;
  234. function V3D2STR(V: TVector3D): String;
  235.  
  236. implementation
  237.  
  238. //-----Global routines-----//
  239.  
  240. function V3D(vx,vy,vz: double): TVector3D;
  241. begin
  242.   with Result do
  243.   begin
  244.     X := vx;
  245.     Y := vy;
  246.     Z := vz;
  247.   end;
  248. end;
  249.  
  250. function V3DXY(V: TVector3D): TVector2D;
  251. begin
  252.   with Result do
  253.   begin
  254.     x := V.x;
  255.     y := V.y;
  256.   end;
  257. end;
  258.  
  259. function V3DXZ(V: TVector3D): TVector2D;
  260. begin
  261.   with Result do
  262.   begin
  263.     x := V.x;
  264.     y := V.z;
  265.   end;
  266. end;
  267.  
  268. function V3DZY(V: TVector3D): TVector2D;
  269. begin
  270.   with Result do
  271.   begin
  272.     x := V.z;
  273.     y := V.y;
  274.   end;
  275. end;
  276.  
  277. function V3D2STR(V: TVector3D): String;
  278. var
  279. SX,SY,SZ: String;
  280. begin
  281.   Str(V.x,SX);
  282.   Str(V.y,SY);
  283.   Str(V.z,SZ);
  284.   Result := '<'+SX+','+SY+','+SZ+'>';
  285. end;
  286.  
  287. function V2D(x,y: double): TVector2D;
  288. var
  289. AResult: TVector2D;
  290. begin
  291.   AResult.x := x;
  292.   AResult.y := y;
  293.   Result := AResult;
  294. end;
  295.  
  296. function V2D2Point(V: TVector2D): TPoint;
  297. begin
  298.   with Result do
  299.   begin
  300.     x := Round(V.x);
  301.     y := Round(V.y);
  302.   end;
  303. end;
  304.  
  305. procedure Register;
  306. begin
  307.   RegisterComponents('Custom', [TAxesView]);
  308. end;
  309.  
  310. //-----TVarList implementation-----//
  311.  
  312. function TVarList.GetIndex(AValue: String): Integer;
  313. var
  314. i: integer;
  315. begin
  316.   if Count>0 then
  317.   begin
  318.     for i := 0 to Count-1 do
  319.     begin
  320.       if PVariableRecord(items[i])^.VarName = AValue then
  321.       begin
  322.         Result := i;
  323.         Exit;
  324.       end;
  325.     end;
  326.   end;
  327.   //Nothing found--return -1 as error code
  328.   Result := -1;
  329. end;
  330.  
  331. function TVarList.GetVars(Index: String): PVariableRecord;
  332. var
  333. ti: integer;
  334. begin
  335.   ti := GetIndex(Index);
  336.   if ti > -1 then
  337.     Result := PVariableRecord(Items[ti])
  338.   else
  339.     Result := nil;
  340. end;
  341.  
  342. function TVarList.NewVar(AName: String; AData: Double): PVariableRecord;
  343. var
  344. VarRec: PVariableRecord;
  345. ti: integer;
  346. begin
  347.   ti := GetIndex(AName);
  348.   if ti = -1 then
  349.   begin
  350.     VarRec := New(PVariableRecord);
  351.     VarRec^.VarName := AName;
  352.     VarRec^.VarData := AData;
  353.     Add(VarRec);
  354.   end
  355.   else
  356.   begin
  357.     VarRec := PVariableRecord(Items[ti]);
  358.     VarRec^.VarData := AData;
  359.   end;
  360.   Result := VarRec;
  361. end;
  362.  
  363. destructor TVarList.Destroy;
  364. begin
  365.   while Count>0 do
  366.   begin
  367.     Dispose(Items[0]);
  368.     Delete(0);
  369.   end;
  370.   inherited Destroy;
  371. end;
  372.  
  373. //-----TExpressionNode implementation-----//
  374.  
  375. constructor TExpressionNode.Create(AOwner: TExpressionNode;
  376. ATree: TExpressionTree);
  377. begin
  378.   inherited Create;
  379.   FParent := AOwner;
  380.   FTree := ATree;
  381.   FChildren := TList.Create;
  382.   FValidValue := False;
  383. end;
  384.  
  385. destructor TExpressionNode.Destroy;
  386. begin
  387.   while FChildren.Count > 0 do
  388.   begin
  389.     TExpressionNode(FChildren.items[0]).Free;
  390.     FChildren.Delete(0);
  391.   end;
  392.   FChildren.Free;
  393.   inherited Destroy;
  394. end;
  395.  
  396. function TExpressionNode.CreateChild: TExpressionNode;
  397. var
  398. tNode: TExpressionNode;
  399. begin
  400.   tNode := TExpressionNode.Create(Self,Tree);
  401.   Children.Add(tNode);
  402.   Result := tNode;
  403. end;
  404.  
  405. function TExpressionNode.Evaluate(SuppressErrors,UseVars: Boolean): Double;
  406. var
  407. tf: double;
  408. i: longint;
  409. invop: boolean;
  410. begin
  411.   //Evaluate the children first
  412.   if Children.Count>0 then
  413.   begin
  414.     for i := 0 to Children.Count-1 do
  415.       TExpressionNode(Children.items[i]).Evaluate(SuppressErrors,UseVars);
  416.   end;
  417.   //Now that children are evaluated, do this node
  418.   case TokenType of
  419.     ttUnknown:
  420.     begin
  421.       //This hasn't been trimmed so just evaluate the first child
  422.       if Children.Count > 0 then
  423.       begin
  424.         NumValue := TExpressionNode(Children.items[0]).
  425.         Evaluate(SuppressErrors,UseVars);
  426.         ValidValue := TExpressionNode(Children.items[0]).ValidValue;
  427.         Result := NumValue;
  428.       end
  429.       else
  430.       begin
  431.         if not SuppressErrors then
  432.         begin
  433.           ShowMessage('Error in evaluation tree: ttUnknown node with no children.');
  434.           Exit;
  435.         end;
  436.       end;
  437.     end;
  438.     ttConstant:
  439.     begin
  440.       if not ValidValue then
  441.       begin
  442.         //Store everything as floats for now
  443.         try
  444.           tf := StrToFloat(Value);
  445.           //Ok, it's a valid float value so store it
  446.           NumValue := tf;
  447.           ValidValue := True;
  448.         except
  449.           //It's not a valid numeric constant!
  450.           on EConvertError do
  451.           begin
  452.             if not SuppressErrors then
  453.             begin
  454.               ShowMessage('Invalid numeric constant: '+Value);
  455.               Exit;
  456.             end;
  457.           end;
  458.         end;
  459.       end;
  460.       Result := NumValue;
  461.     end;
  462.     ttVariable:
  463.     begin
  464.       if UseVars then
  465.       begin
  466.         //Make sure variable hasn't changed from token
  467.         if not Assigned(VarPointer) or (VarPointer^.VarName <> Value) then
  468.         begin
  469.           //Find new variable or create one if needed
  470.           VarPointer := Tree.VarList.Vars[Value];
  471.           if VarPointer = nil then
  472.             VarPointer := Tree.VarList.NewVar(Value,0);
  473.         end;
  474.         //Variable is now valid
  475.         NumValue := VarPointer^.VarData;
  476.         ValidValue := True;
  477.       end
  478.       else
  479.         ValidValue := False;
  480.     end;
  481.     ttOperation:
  482.     begin
  483.       //This is where the math takes place
  484.       ValidValue := false;
  485.       invop := true;
  486.       if Value = '+' then
  487.       begin
  488.         if Children.Count = 2 then
  489.         begin
  490.           NumValue := TExpressionNode(Children.items[0]).NumValue+
  491.           TExpressionNode(Children.items[1]).NumValue;
  492.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  493.           TExpressionNode(Children.items[1]).ValidValue;
  494.           invop := false;
  495.         end
  496.         else
  497.         begin
  498.           ValidValue := False;
  499.           if not SuppressErrors then
  500.           begin
  501.             ShowMessage('Error: addition operation with '+
  502.             IntToStr(Children.Count)+' values.');
  503.             Exit;
  504.           end;
  505.         end;
  506.       end;
  507.       if Value = '-' then
  508.       begin
  509.         if Children.Count = 2 then
  510.         begin
  511.           NumValue := TExpressionNode(Children.items[0]).NumValue-
  512.           TExpressionNode(Children.items[1]).NumValue;
  513.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  514.           TExpressionNode(Children.items[1]).ValidValue;
  515.           invop := false;
  516.         end
  517.         else
  518.         begin
  519.           ValidValue := False;
  520.           if not SuppressErrors then
  521.           begin
  522.             ShowMessage('Error: subtraction operation with '+
  523.             IntToStr(Children.Count)+' values.');
  524.             Exit;
  525.           end;
  526.         end;
  527.       end;
  528.       if Value = '*' then
  529.       begin
  530.         if Children.Count = 2 then
  531.         begin
  532.           NumValue := TExpressionNode(Children.items[0]).NumValue*
  533.           TExpressionNode(Children.items[1]).NumValue;
  534.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  535.           TExpressionNode(Children.items[1]).ValidValue;
  536.           invop := false;
  537.         end
  538.         else
  539.         begin
  540.           ValidValue := False;
  541.           if not SuppressErrors then
  542.           begin
  543.             ShowMessage('Error: multiplacation operation with '+
  544.             IntToStr(Children.Count)+' values.');
  545.             Exit;
  546.           end;
  547.         end;
  548.       end;
  549.       if Value = '/' then
  550.       begin
  551.         if Children.Count = 2 then
  552.         begin
  553.           NumValue := TExpressionNode(Children.items[0]).NumValue/
  554.           TExpressionNode(Children.items[1]).NumValue;
  555.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  556.           TExpressionNode(Children.items[1]).ValidValue;
  557.           invop := false;
  558.         end
  559.         else
  560.         begin
  561.           ValidValue := False;
  562.           if not SuppressErrors then
  563.           begin
  564.             ShowMessage('Error: division operation with '+
  565.             IntToStr(Children.Count)+' values.');
  566.             Exit;
  567.           end;
  568.         end;
  569.       end;
  570.       if Value = 'div' then
  571.       begin
  572.         if Children.Count = 2 then
  573.         begin
  574.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue/
  575.           TExpressionNode(Children.items[1]).NumValue);
  576.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  577.           TExpressionNode(Children.items[1]).ValidValue;
  578.           invop := false;
  579.         end
  580.         else
  581.         begin
  582.           ValidValue := False;
  583.           if not SuppressErrors then
  584.           begin
  585.             ShowMessage('Error: integer division operation with '+
  586.             IntToStr(Children.Count)+' values.');
  587.             Exit;
  588.           end;
  589.         end;
  590.       end;
  591.       if Value = 'mod' then
  592.       begin
  593.         if Children.Count = 2 then
  594.         begin
  595.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue) mod
  596.           Round(TExpressionNode(Children.items[1]).NumValue);
  597.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  598.           TExpressionNode(Children.items[1]).ValidValue;
  599.           invop := false;
  600.         end
  601.         else
  602.         begin
  603.           ValidValue := False;
  604.           if not SuppressErrors then
  605.           begin
  606.             ShowMessage('Error: modulo operation with '+
  607.             IntToStr(Children.Count)+' values.');
  608.             Exit;
  609.           end;
  610.         end;
  611.       end;
  612.       if Value = 'and' then
  613.       begin
  614.         if Children.Count = 2 then
  615.         begin
  616.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue) and
  617.           Round(TExpressionNode(Children.items[1]).NumValue);
  618.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  619.           TExpressionNode(Children.items[1]).ValidValue;
  620.           invop := false;
  621.         end
  622.         else
  623.         begin
  624.           ValidValue := False;
  625.           if not SuppressErrors then
  626.           begin
  627.             ShowMessage('Error: and operation with '+
  628.             IntToStr(Children.Count)+' values.');
  629.             Exit;
  630.           end;
  631.         end;
  632.       end;
  633.       if Value = 'or' then
  634.       begin
  635.         if Children.Count = 2 then
  636.         begin
  637.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue) or
  638.           Round(TExpressionNode(Children.items[1]).NumValue);
  639.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  640.           TExpressionNode(Children.items[1]).ValidValue;
  641.           invop := false;
  642.         end
  643.         else
  644.         begin
  645.           ValidValue := False;
  646.           if not SuppressErrors then
  647.           begin
  648.             ShowMessage('Error: or operation with '+
  649.             IntToStr(Children.Count)+' values.');
  650.             Exit;
  651.           end;
  652.         end;
  653.       end;
  654.       if Value = 'xor' then
  655.       begin
  656.         if Children.Count = 2 then
  657.         begin
  658.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue) xor
  659.           Round(TExpressionNode(Children.items[1]).NumValue);
  660.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  661.           TExpressionNode(Children.items[1]).ValidValue;
  662.           invop := false;
  663.         end
  664.         else
  665.         begin
  666.           ValidValue := False;
  667.           if not SuppressErrors then
  668.           begin
  669.             ShowMessage('Error: addition operation with '+
  670.             IntToStr(Children.Count)+' values.');
  671.             Exit;
  672.           end;
  673.         end;
  674.       end;
  675.       if Value = '=' then
  676.       begin
  677.         if Children.Count = 2 then
  678.         begin
  679.           NumValue := Ord(TExpressionNode(Children.items[0]).NumValue=
  680.           TExpressionNode(Children.items[1]).NumValue);
  681.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  682.           TExpressionNode(Children.items[1]).ValidValue;
  683.           invop := false;
  684.         end
  685.         else
  686.         begin
  687.           ValidValue := False;
  688.           if not SuppressErrors then
  689.           begin
  690.             ShowMessage('Error: equative operation with '+
  691.             IntToStr(Children.Count)+' values.');
  692.             Exit;
  693.           end;
  694.         end;
  695.       end;
  696.       if Value = '^' then
  697.       begin
  698.         if Children.Count = 2 then
  699.         begin
  700.           NumValue := Exp(TExpressionNode(Children.items[1]).NumValue *
  701.           Ln(TExpressionNode(Children.items[0]).NumValue));
  702.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  703.           TExpressionNode(Children.items[1]).ValidValue;
  704.           invop := false;
  705.         end
  706.         else
  707.         begin
  708.           ValidValue := False;
  709.           if not SuppressErrors then
  710.           begin
  711.             ShowMessage('Error: exponential operation with '+
  712.             IntToStr(Children.Count)+' values.');
  713.             Exit;
  714.           end;
  715.         end;
  716.         if invop then
  717.         begin
  718.           if not SuppressErrors then
  719.             ShowMessage('Error: invalid operation '+Value);
  720.         end
  721.       end;
  722.     end;
  723.   end;
  724.   Result := NumValue;
  725. end;
  726.  
  727.  
  728.  
  729. //-----TExpressionTree implementation-----//
  730.  
  731. constructor TExpressionTree.Create;
  732. begin
  733.   inherited Create;
  734.   FCheckSyntax := True;
  735.   FTokens := TStringList.Create;
  736. end;
  737.  
  738. destructor TExpressionTree.Destroy;
  739. begin
  740.   if Assigned(FTopNode) then
  741.     FTopNode.Free;
  742.   FTokens.Free;
  743.   inherited Destroy;
  744. end;
  745.  
  746. procedure TExpressionTree.RemoveBadTokens;
  747. var
  748. i: longint;
  749. begin
  750.   if Tokens.Count > 0 then
  751.   begin
  752.     //Cut out extra parentheses.
  753.     i := 1;
  754.     repeat
  755.       if (Tokens[i-1] = '(') and (Tokens[i+1] = ')') then
  756.       begin
  757.         //No need for parentheses around a single token
  758.         Tokens.Delete(i-1);
  759.         Tokens.Delete(i);
  760.         i := 1;
  761.       end;
  762.       Inc(i);
  763.     until (i>(Tokens.Count-2))
  764.   end;
  765. end;
  766.  
  767. procedure TExpressionTree.MakeTokens;
  768. var
  769. incount,start: longint;
  770. begin
  771.   Tokens.Clear;
  772.   incount := 1;
  773.   start := 1;
  774.   repeat
  775.     //Read new token until we find a valid operation char or a space
  776.     while not (FExpression[incount] in ValidOps)
  777.     and not (FExpression[incount] = ' ') do
  778.     begin
  779.       //It's still a valid token so keep reading
  780.       Inc(incount);
  781.       if (incount>Length(FExpression)) then
  782.       begin
  783.         //We've gone past the end of the string
  784.         //Write the token and exit
  785.         Tokens.Add(Copy(FExpression,start,incount-start));
  786.         Exit;
  787.       end;
  788.     end;
  789.     //We've found a valid operation or space character
  790.     //Record token before operation or space
  791.     if (incount-start)>0 then
  792.       Tokens.Add(Copy(FExpression,start,incount-start));
  793.     //Record an operation, but discard a space
  794.     if FExpression[incount] in ValidOps then
  795.       Tokens.Add(Copy(FExpression,incount,1));
  796.     start := incount+1;
  797.     incount := start;
  798.   until (start>Length(FExpression));
  799. end;
  800.  
  801. procedure TExpressionTree.SetExpression(AValue: String);
  802. var
  803. i,c: longint;
  804. CNode,tNode: TExpressionNode;
  805. CToken: String;
  806. tf: double;
  807.  
  808. function IsLowerOp: Boolean;
  809. begin
  810.   Result := (CToken='+') or (CToken='-') or (CToken='=') or (CToken='or') or
  811.   (CToken='and') or (CToken='xor');
  812. end;
  813.  
  814. function IsMiddleOp: Boolean;
  815. begin
  816.   Result := (CToken='*') or (CToken='/') or (CToken='div') or (CToken='mod');
  817. end;
  818.  
  819. begin
  820.   if (AValue<>FExpression) and (AValue <> '') then
  821.   begin
  822.     if CheckSyntax then
  823.     begin
  824.       c := 0;
  825.       for i := 1 to Length(AValue) do
  826.       begin
  827.         case AValue[i] of
  828.           '(': Inc(c);
  829.           ')': Dec(c);
  830.         end;
  831.       end;
  832.       if (c<>0) then
  833.       begin
  834.         ShowMessage('Error in syntax: parentheses unbalanced at '+IntToStr(c));
  835.         Exit;
  836.       end;
  837.     end;
  838.     //No syntax errors found yet--set property and clear old tree
  839.     FExpression := AValue;
  840.     if Assigned(FTopNode) then
  841.       FTopNode.Free;
  842.     FTopNode := TExpressionNode.Create(nil,Self);
  843.     //Parse expression so it's ready for tree generation
  844.     MakeTokens;
  845.     //Remove any tokens that are useless or will cause undesired behavior
  846.     RemoveBadTokens;
  847.     //Let's make the tree
  848.     if Tokens.Count>0 then
  849.     begin
  850.       CNode := FTopNode;
  851.       for i := 0 to Tokens.Count-1 do
  852.       begin
  853.         CToken := Tokens.strings[i];
  854.         if CToken='(' then
  855.         begin
  856.           CNode := CNode.CreateChild;
  857.           //Create temporary token for reference of order-of-operations code
  858.           CNode.Value := '(';
  859.           CNode.TokenType := ttOperation;
  860.           CNode := CNode.CreateChild;
  861.           Continue;
  862.         end;
  863.         if IsLowerOp or (Assigned(CNode.Parent) and (CNode.Parent.Value='^')
  864.         and IsMiddleOp) then
  865.         begin
  866.           //Low priority or after an exponent--go up the tree
  867.           if not Assigned(CNode.Parent) then
  868.           begin
  869.             ShowMessage('Error in expression: '+FExpression);
  870.             Exit;
  871.           end;
  872.           repeat
  873.             CNode := CNode.Parent;
  874.           until  not Assigned(CNode.Parent) or
  875.           (CNode.TokenType<>ttOperation) or (CNode.Parent.Value = '(');
  876.           if CNode.TokenType = ttOperation then
  877.           begin
  878.             //Create a new higher level node in-between CNode and CNode.Parent
  879.             //If CNode.Parent is nil then we must setup a new TopNode field
  880.             if not Assigned(CNode.Parent) then
  881.             begin
  882.               if not (CNode = FTopNode) then
  883.               begin
  884.                 ShowMessage('Expression Evaluator Error: '+
  885.                 'Node with nil parent is not top node!');
  886.                 Exit;
  887.               end;
  888.               FTopNode := TExpressionNode.Create(nil,Self);
  889.               FTopNode.Children.Add(CNode);
  890.               CNode.Parent := FTopNode;
  891.             end
  892.             else
  893.             begin
  894.               //Otherwise just insert the new node
  895.               tNode := TExpressionNode.Create(CNode.Parent,Self);
  896.               tNode.Children.Add(CNode);
  897.               //Don't forget to reset children of Parent node
  898.               CNode.Parent.Children.Remove(CNode);
  899.               CNode.Parent.Children.Add(tNode);
  900.               CNode.Parent := tNode;
  901.             end;
  902.           end
  903.           else
  904.           begin
  905.             //There is no operation at this node currently--replace the node
  906.             //data for this operation and continue loop
  907.             CNode.TokenType := ttOperation;
  908.             CNode.Value := CToken;
  909.             Continue;
  910.           end;
  911.           //Node inserted--set current node to parent so that operation can
  912.           //be inserted
  913.           CNode := CNode.Parent;
  914.           CNode.TokenType := ttOperation;
  915.           CNode.Value := CToken;
  916.           Continue;
  917.         end;
  918.         if IsMiddleOp or (CToken='^') then
  919.         begin
  920.           //Middle operation that isn't past an exponent or an exponent--go down
  921.           if not Assigned(CNode.Parent) then
  922.           begin
  923.             ShowMessage('Error in expression: '+FExpression);
  924.             Exit;
  925.           end;
  926.           if CNode.Parent.TokenType = ttOperation then
  927.           begin
  928.             //Insert node before CNode
  929.             tNode := TExpressionNode.Create(CNode,Self);
  930.             while (CNode.Children.Count>0) do
  931.             begin
  932.               TExpressionNode(CNode.Children.items[0]).Parent := tNode;
  933.               tNode.Children.Add(CNode.Children.items[0]);
  934.               CNode.Children.Delete(0);
  935.             end;
  936.             tNode.Value := CNode.Value;
  937.             tNode.TokenType := CNode.TokenType;
  938.             CNode.Children.Add(tNode);
  939.           end
  940.           else
  941.             CNode := CNode.Parent;
  942.           CNode.TokenType := ttOperation;
  943.           CNode.Value := CToken;
  944.           Continue;
  945.         end;
  946.         if CToken = ')' then
  947.         begin
  948.           //We need to backtrack through tree to find our origin--
  949.           {while Assigned(CNode.Parent)
  950.           and (CNode.Parent.TokenType<>ttUnknown) do CNode := CNode.Parent;}
  951.           //Look for '(' marker
  952.           repeat
  953.             CNode := CNode.Parent;
  954.           until (CNode.Parent.Value = '(');
  955.           //Delete the marker and setup CNode
  956.           tNode := CNode;
  957.           CNode := tNode.Parent;
  958.           CNode.Parent.Children.Remove(CNode);
  959.           while (CNode.Children.Count>0) do
  960.           begin
  961.             TExpressionNode(CNode.Children.items[0]).Parent := CNode.Parent;
  962.             CNode.Parent.Children.Add(CNode.Children.items[0]);
  963.             CNode.Children.Delete(0);
  964.           end;
  965.           CNode.Free;
  966.           CNode := tNode;
  967.           //Check to see if TopNode is already assigned and if so insert a new
  968.           //node above it--assuming we're at the TopNode
  969.           if not Assigned(CNode.Parent) then
  970.           begin
  971.             if not (CNode = FTopNode) then
  972.             begin
  973.               ShowMessage('Expression Evaluator Error: '+
  974.               'Node with nil parent is not top node!');
  975.               Exit;
  976.             end;
  977.             //Create new top node
  978.             FTopNode := TExpressionNode.Create(nil,Self);
  979.             FTopNode.Children.Add(CNode);
  980.             CNode.Parent := FTopNode;
  981.           end;
  982.           Continue;
  983.         end;
  984.         //It's not a symbol or an operator, so it must be something else
  985.         //Check to see if it's a valid numeric constant
  986.         try
  987.           tf := StrToFloat(CToken);
  988.           //It's a valid constant since no exception has been raised
  989.           //Create child node for constant
  990.           CNode := CNode.CreateChild;
  991.           CNode.TokenType := ttConstant;
  992.           CNode.Value := CToken;
  993.         except
  994.           on EConvertError do
  995.           begin
  996.             //It's not a valid number, so let's assume it's a variable
  997.             CNode := CNode.CreateChild;
  998.             CNode.TokenType := ttVariable;
  999.             CNode.Value := CToken;
  1000.           end;
  1001.         end;
  1002.         //Continue for loop through tokens
  1003.       end;
  1004.     end;
  1005.   end;
  1006. end;
  1007.  
  1008. //-----TAxesView implementation-----//
  1009.  
  1010. procedure TAxesView.DrawGrid;
  1011. var
  1012. i: longint;
  1013. CVector: TVector2D;
  1014. begin
  1015.   with Canvas do
  1016.   begin
  1017.     Pen.Color := GridColor;
  1018.     Pen.Width := 1;
  1019.     for i := 0 to FGrid.Count-1 do
  1020.     begin
  1021.       CVector := FGrid.Data[i];
  1022.       PenPos := Point(0,Round(CVector.y));
  1023.       LineTo(Width-1,Round(CVector.y));
  1024.       PenPos := Point(Round(CVector.x),0);
  1025.       LineTo(Round(CVector.x),Height-1);
  1026.     end;
  1027.   end;
  1028. end;
  1029.  
  1030. procedure TAxesView.DrawAxes;
  1031. begin
  1032.   with Canvas do
  1033.   begin
  1034.     Pen.Width := 2;
  1035.     Pen.Color := XAxisColor;
  1036.     PenPos := (Point(0,Round(Origin.y)));
  1037.     LineTo(Width-1,Round(Origin.y));
  1038.     Pen.Color := YAxisColor;
  1039.     PenPos := (Point(Round(Origin.x),0));
  1040.     LineTo(Round(Origin.x),Height-1);
  1041.   end;
  1042. end;
  1043.  
  1044. procedure TAxesView.DrawLabels;
  1045. var
  1046. i: longint;
  1047. begin
  1048.   Canvas.Brush.Style := bsClear;
  1049.   if Labels.Count > 0 then
  1050.   begin
  1051.     for i := 0 to Labels.Count-1 do
  1052.     begin
  1053.       with TDataLabel(Labels.items[i]) do
  1054.         Canvas.TextOut(x,y,Data);
  1055.     end;
  1056.   end;
  1057. end;
  1058.  
  1059. procedure TAxesView.Paint;
  1060. begin
  1061.   //Draw grid
  1062.   if ShowGrid then DrawGrid;
  1063.   //Draw axes
  1064.   if ShowAxes then DrawAxes;
  1065.   //Draw labels
  1066.   if ShowLabels then DrawLabels;
  1067.   if Assigned(FOnPaint) then
  1068.     FOnPaint(Self);
  1069. end;
  1070.  
  1071. procedure TAxesView.RecalcScale;
  1072. var
  1073. diffx,diffy,i,k,tv: longint;
  1074. j: double;
  1075. CXMod,CYMod: Integer;
  1076. DL: TDataLabel;
  1077. ts,tsb: string;
  1078. CVector: TVector2D;
  1079.  
  1080. function max(a,b: longint): longint;
  1081. begin
  1082.   if (a>b) then
  1083.     Result := a
  1084.   else
  1085.     Result := b;
  1086. end;
  1087.  
  1088. begin
  1089.   FRXScale := Width/(XMax-XMin);
  1090.   FRYScale := Height/(YMin-YMax);
  1091.   if ShowAxes or ShowGrid or ShowLabels then FOrigin := GetRealCoord(V2D(0,0));
  1092.   if ShowGrid then
  1093.   begin
  1094.     //Prepare for maximum possible allocation
  1095.     FGrid.Count :=
  1096.     abs(Round((XMax-XMin)/XScale))+abs(Round((YMax-YMin)/YScale))*2;
  1097.     diffx := abs(Round(GetRealCoord(V2D(XScale,0)).x-Origin.x));
  1098.     diffy := abs(Round(GetRealCoord(V2D(0,YScale)).y-Origin.y));
  1099.     j := 0;
  1100.     //Do -XY first
  1101.     i := Round(Origin.x);
  1102.     k := Round(Origin.y);
  1103.     repeat
  1104.       i := i - diffx;
  1105.       k := k - diffy;
  1106.       FGrid.Data[Round(j)] := V2D(i,k);
  1107.       j := j + 1;
  1108.     until (i<0)and(k<0);
  1109.     //Do +XY next
  1110.     i := Round(Origin.x);
  1111.     k := Round(Origin.y);
  1112.     repeat
  1113.       i := i + diffx;
  1114.       k := k + diffy;
  1115.       FGrid.Data[Round(j)] := V2D(i,k);
  1116.       j := j + 1;
  1117.     until (i>=Width) and (k>=Height);
  1118.     FGrid.Count := Round(j);
  1119.   end;
  1120.   if ShowLabels then
  1121.   begin
  1122.     //Free old information from Labels list
  1123.     while (Labels.Count > 0) do
  1124.     begin
  1125.       TDataLabel(Labels.items[0]).Free;
  1126.       Labels.Delete(0);
  1127.     end;
  1128.     //Setup variables for scale including spacing
  1129.     CVector := GetRealCoord(V2D(XMin+XScale,YMax-YScale));
  1130.     Str(XMin:0:Decimals,ts);
  1131.     Str(XMax:0:Decimals,tsb);
  1132.     CXMod := Trunc(max(Canvas.TextWidth(ts),
  1133.     Canvas.TextWidth(tsb))*1.05/(CVector.x))+1;
  1134.     Str(YMin:0:Decimals,ts);
  1135.     Str(YMax:0:Decimals,tsb);
  1136.     CYMod := Trunc(max(Canvas.TextHeight(ts),
  1137.     Canvas.TextHeight(tsb))*1.05/(CVector.y))+1;
  1138.     //Store the actual labels
  1139.     //Do X- first
  1140.     j := -(CXMod*XScale);
  1141.     repeat
  1142.       DL := TDataLabel.Create;
  1143.       Str(j:0:Decimals,ts);
  1144.       DL.Data := ts;
  1145.       tv := Round(GetRealCoord(V2D(j,0)).x);
  1146.       DL.x := tv-(Canvas.TextWidth(ts) div 2);
  1147.       if (AlignLabelX = aaNegative) then
  1148.         DL.y := Round(Origin.y) + 1
  1149.       else
  1150.         DL.y := Round(Origin.y)-Canvas.TextHeight(ts)-1;
  1151.       Labels.Add(DL);
  1152.       j := j - (CXMod*XScale);
  1153.     until (j < XMin);
  1154.     //Do X+ now
  1155.     j := (CXMod*XScale);
  1156.     repeat
  1157.       DL := TDataLabel.Create;
  1158.       Str(j:0:Decimals,ts);
  1159.       DL.Data := ts;
  1160.       tv := Round(GetRealCoord(V2D(j,0)).x);
  1161.       DL.x := tv-(Canvas.TextWidth(ts) div 2);
  1162.       if (AlignLabelX = aaNegative) then
  1163.         DL.y := Round(Origin.y) + 1
  1164.       else
  1165.         DL.y := Round(Origin.y)-Canvas.TextHeight(ts)-1;
  1166.       Labels.Add(DL);
  1167.       j := j + (CXMod*XScale);
  1168.     until (j > XMax);
  1169.     //Do Y- now
  1170.     j := -(CYMod*YScale);
  1171.     repeat
  1172.       DL := TDataLabel.Create;
  1173.       Str(j:0:Decimals,ts);
  1174.       DL.Data := ts;
  1175.       tv := Round(GetRealCoord(V2D(0,j)).y);
  1176.       if (AlignLabelY = aaNegative) then
  1177.         DL.x := Round(Origin.X)-Canvas.TextWidth(ts)-1
  1178.       else
  1179.         DL.x := Round(Origin.X)+1;
  1180.       DL.y := tv-(Canvas.TextHeight(ts) div 2);
  1181.       Labels.Add(DL);
  1182.       j := j - (CYMod*YScale);
  1183.     until (j < YMin);
  1184.     //Do Y+ now
  1185.     j := (CYMod*YScale);
  1186.     repeat
  1187.       DL := TDataLabel.Create;
  1188.       Str(j:0:Decimals,ts);
  1189.       DL.Data := ts;
  1190.       tv := Round(GetRealCoord(V2D(0,j)).y);
  1191.       if (AlignLabelY = aaNegative) then
  1192.         DL.x := Round(Origin.X)-Canvas.TextWidth(ts)-1
  1193.       else
  1194.         DL.x := Round(Origin.X)+1;
  1195.       DL.y := tv-(Canvas.TextHeight(ts) div 2);
  1196.       Labels.Add(DL);
  1197.       j := j + (CYMod*YScale);
  1198.     until (j > YMax);
  1199.   end;
  1200. end;
  1201.  
  1202. procedure TAxesView.DoAutoPan(X,Y: Integer);
  1203. var
  1204. V: TVector2D;
  1205. begin
  1206.   V := GetMathCoord(V2D(X,Y));
  1207.   if (X<5) then FXMin := FXMin-FXScale
  1208.   else
  1209.   begin
  1210.     if (X>Width-5) then FXMax := FXMax+FXScale
  1211.     else
  1212.     begin
  1213.       if (Y<5) then FYMax := FYMax+FYScale
  1214.       else
  1215.       begin
  1216.         if (Y>Height-5) then FYMin := FYMin-FYScale
  1217.         else
  1218.           Exit;
  1219.       end;
  1220.     end;
  1221.   end;
  1222.   RecalcScale;
  1223.   V := GetRealCoord(V);
  1224.   SetCursorPos(ClientOrigin.X+Round(V.X),ClientOrigin.Y+Round(V.Y));
  1225. end;
  1226.  
  1227. function TAxesView.GetRealCoord(InV: TVector2D): TVector2D;
  1228. begin
  1229.   if Assigned(FOnGetRealCoord) then
  1230.     FOnGetRealCoord(InV);
  1231.   with Result do
  1232.   begin
  1233.     x := RXScale*(InV.x-XMin);
  1234.     y := RYScale*(InV.y-YMax);
  1235.   end;
  1236. end;
  1237.  
  1238. function TAxesView.GetMathCoord(Inv: TVector2D): TVector2D;
  1239. begin
  1240.   with InV do
  1241.   begin
  1242.     x := (x/RXScale)+XMin;
  1243.     y := (y/RYScale)+YMax;
  1244.   end;
  1245.   if Assigned(OnGetMathCoord) then
  1246.     FOnGetMathCoord(InV);
  1247.   Result := InV;
  1248. end;
  1249.  
  1250. procedure TAxesView.Zoom(Percent: Integer);
  1251. begin
  1252.   if Percent>0 then
  1253.   begin
  1254.     FXMin := FXMin*(Percent/100);
  1255.     FXMax := FXMax*(Percent/100);
  1256.     FYMin := FYMin*(Percent/100);
  1257.     FYMax := FYMax*(Percent/100);
  1258.     RecalcScale;
  1259.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1260.   end;
  1261. end;
  1262.  
  1263. procedure TAxesView.SetScale(AXMin,AXMax,AXScale,AYMin,AYMax,AYScale: Double);
  1264. begin
  1265.   FXMin := AXMin;
  1266.   FXMax := AXMax;
  1267.   FXScale := AXScale;
  1268.   FYMin := AYMin;
  1269.   FYMax := AYMax;
  1270.   FYScale := AYScale;
  1271.   RecalcScale;
  1272.   if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1273. end;
  1274.  
  1275. constructor TAxesView.Create(AOwner: TComponent);
  1276. begin
  1277.   inherited Create(AOwner);
  1278.   FGrid := TDataSet2D.Create(20);
  1279.   //Setup default values
  1280.   FXMin := -100;
  1281.   FXMax := 100;
  1282.   FXScale := 10;
  1283.   FYMin := -100;
  1284.   FYMax := 100;
  1285.   FYScale := 10;
  1286.   FDecimals := 0;
  1287.   FShowGrid := True;
  1288.   FShowAxes := True;
  1289.   FShowLabels := True;
  1290.   FLabels := TList.Create;
  1291.   FXAxisColor := clBlack;
  1292.   FYAxisColor := clBlack;
  1293.   FGridColor := clSilver;
  1294.   FAutoUpdate := True;
  1295.   Color := clWhite;
  1296.   Width := 200;
  1297.   Height := 200;
  1298.   //Hook events in object
  1299.   Font.OnChange := FontChange;
  1300. end;
  1301.  
  1302. destructor TAxesView.Destroy;
  1303. begin
  1304.   FGrid.Free;
  1305.   inherited Destroy;
  1306. end;
  1307.  
  1308. procedure TAxesView.WMSize(var Message: TWMSize);
  1309. begin
  1310.   if (Message.Width < 50) or (Message.Height < 50) then Exit;
  1311.   inherited;
  1312.   if not (csLoading in ComponentState) then
  1313.   begin
  1314.     RecalcScale;
  1315.     Refresh;
  1316.   end;
  1317. end;
  1318.  
  1319. procedure TAxesView.FontChange(Sender: TObject);
  1320. begin
  1321.   Canvas.Font.Assign(Font);
  1322.   if (csDesigning in ComponentState) or AutoUpdate then
  1323.   begin
  1324.     RecalcScale;
  1325.     Refresh;
  1326.   end;
  1327. end;
  1328.  
  1329. procedure TAxesView.SetDecimals(AValue: Integer);
  1330. begin
  1331.   if (AValue<>FDecimals) and (AValue>=0) and (AValue<9) then
  1332.   begin
  1333.     FDecimals := AValue;
  1334.     if (csDesigning in ComponentState) or AutoUpdate then
  1335.     begin
  1336.       RecalcScale;
  1337.       Refresh;
  1338.     end;
  1339.   end;
  1340. end;
  1341.  
  1342. procedure TAxesView.SetXMin(AValue: Double);
  1343. begin
  1344.   if (AValue <> FXMin) and (AValue < FXMax) then
  1345.   begin
  1346.     FXMin := AValue;
  1347.     if (csDesigning in ComponentState) or AutoUpdate then
  1348.     begin
  1349.       RecalcScale;
  1350.       Refresh;
  1351.     end;
  1352.   end;
  1353. end;
  1354.  
  1355. procedure TAxesView.SetXMax(AValue: Double);
  1356. begin
  1357.   if (AValue <> FXMax) and (AValue > FXMin) then
  1358.   begin
  1359.     FXMax := AValue;
  1360.     if (csDesigning in ComponentState) or AutoUpdate then
  1361.     begin
  1362.       RecalcScale;
  1363.       Refresh;
  1364.     end;
  1365.   end;
  1366. end;
  1367.  
  1368. procedure TAxesView.SetXScale(AValue: Double);
  1369. begin
  1370.   if AValue <> FXScale then
  1371.   begin
  1372.     FXScale := AValue;
  1373.     if (csDesigning in ComponentState) or AutoUpdate then
  1374.     begin
  1375.       RecalcScale;
  1376.       Refresh;
  1377.     end;
  1378.   end;
  1379. end;
  1380.  
  1381. procedure TAxesView.SetYMin(AValue: Double);
  1382. begin
  1383.   if (AValue <> FYMin) and (AValue<FYMax) then
  1384.   begin
  1385.     FYMin := AValue;
  1386.     if (csDesigning in ComponentState) or AutoUpdate then
  1387.     begin
  1388.       RecalcScale;
  1389.       Refresh;
  1390.     end;
  1391.   end;
  1392. end;
  1393.  
  1394. procedure TAxesView.SetYMax(AValue: Double);
  1395. begin
  1396.   if (AValue <> FYMax) and (AValue>FYMin) then
  1397.   begin
  1398.     FYMax := AValue;
  1399.     if (csDesigning in ComponentState) or AutoUpdate then
  1400.     begin
  1401.       RecalcScale;
  1402.       Refresh;
  1403.     end;
  1404.   end;
  1405. end;
  1406.  
  1407. procedure TAxesView.SetYScale(AValue: Double);
  1408. begin
  1409.   if AValue <> FYScale then
  1410.   begin
  1411.     FYScale := AValue;
  1412.     if (csDesigning in ComponentState) or AutoUpdate then
  1413.     begin
  1414.       RecalcScale;
  1415.       Refresh;
  1416.     end;
  1417.   end;
  1418. end;
  1419.  
  1420. procedure TAxesView.SetShowGrid(AValue: Boolean);
  1421. begin
  1422.   if AValue <> FShowGrid then
  1423.   begin
  1424.     FShowGrid := AValue;
  1425.     if (csDesigning in ComponentState) or AutoUpdate then
  1426.     begin
  1427.       RecalcScale;
  1428.       Refresh;
  1429.     end;
  1430.   end;
  1431. end;
  1432.  
  1433. procedure TAxesView.SetShowAxes(AValue: Boolean);
  1434. begin
  1435.   if AValue <> FShowAxes then
  1436.   begin
  1437.     FShowAxes := AValue;
  1438.     if (csDesigning in ComponentState) or AutoUpdate then
  1439.     begin
  1440.       RecalcScale;
  1441.       Refresh;
  1442.     end;
  1443.   end;
  1444. end;
  1445.  
  1446. procedure TAxesView.SetAlignLabelX(AValue: TAxesAlign);
  1447. begin
  1448.   if AValue<>FAlignLabelX then
  1449.   begin
  1450.     FAlignLabelX := AValue;
  1451.     if (csDesigning in ComponentState) or AutoUpdate then
  1452.     begin
  1453.       RecalcScale;
  1454.       Refresh;
  1455.     end;
  1456.   end;
  1457. end;
  1458.  
  1459. procedure TAxesView.SetAlignLabelY(AValue: TAxesAlign);
  1460. begin
  1461.   if AValue<>FAlignLabelY then
  1462.   begin
  1463.     FAlignLabelY := AValue;
  1464.     if (csDesigning in ComponentState) or AutoUpdate then
  1465.     begin
  1466.       RecalcScale;
  1467.       Refresh;
  1468.     end;
  1469.   end;
  1470. end;
  1471.  
  1472. procedure TAxesView.SetShowLabels(AValue: Boolean);
  1473. begin
  1474.   if AValue <> FShowLabels then
  1475.   begin
  1476.     FShowLabels := AValue;
  1477.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1478.   end;
  1479. end;
  1480.  
  1481. procedure TAxesView.SetXAxisColor(AValue: TColor);
  1482. begin
  1483.   if AValue <> FXAxisColor then
  1484.   begin
  1485.     FXAxisColor := AValue;
  1486.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1487.   end;
  1488. end;
  1489.  
  1490. procedure TAxesView.SetYAxisColor(AValue: TColor);
  1491. begin
  1492.   if AValue <> FYAxisColor then
  1493.   begin
  1494.     FYAxisColor := AValue;
  1495.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1496.   end;
  1497. end;
  1498.  
  1499. procedure TAxesView.SetGridColor(AValue: TColor);
  1500. begin
  1501.   if AValue <> FGridColor then
  1502.   begin
  1503.     FGridColor := AValue;
  1504.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1505.   end;
  1506. end;
  1507.  
  1508. //-----TDataSet2D implementation-----//
  1509.  
  1510. procedure TDataSet2D.SetData(Index: longint; AValue: TVector2D);
  1511. begin
  1512.   with TVector2D(Ptr(Longint(FData)+(Index*SizeOf(TVector2D)))^) do
  1513.   begin
  1514.     x := AValue.x;
  1515.     y := AValue.y;
  1516.   end;
  1517. end;
  1518.  
  1519. function TDataSet2D.GetData(Index: longint): TVector2D;
  1520. begin
  1521.   with TVector2D(Ptr(Longint(FData)+(Index*SizeOf(TVector2D)))^) do
  1522.   begin
  1523.     Result.x := x;
  1524.     Result.y := y;
  1525.   end;
  1526. end;
  1527.  
  1528. procedure TDataSet2D.SetCount(AValue: longint);
  1529. begin
  1530.   if AValue <> FCount then
  1531.   begin
  1532.     FCount := AValue;
  1533.     ReAllocMem(FData,AValue*SizeOf(TVector2D));
  1534.   end;
  1535. end;
  1536.  
  1537. constructor TDataSet2D.Create(ACount: longint);
  1538. begin
  1539.   inherited Create;
  1540.   FCount := ACount;
  1541.   GetMem(FData,ACount*SizeOf(TVector2D));
  1542. end;
  1543.  
  1544. destructor TDataSet2D.Destroy;
  1545. begin
  1546.   FreeMem(FData,FCount*SizeOf(TVector2D));
  1547.   inherited Destroy;
  1548. end;
  1549.  
  1550. //-----TDataSet3D implementation-----//
  1551.  
  1552. procedure TDataSet3D.SetData(Index: longint; AValue: TVector3D);
  1553. begin
  1554.   with TVector3D(Ptr(Longint(FData)+(Index*SizeOf(TVector3D)))^) do
  1555.   begin
  1556.     x := AValue.x;
  1557.     y := AValue.y;
  1558.     z := AValue.z;
  1559.   end;
  1560. end;
  1561.  
  1562. function TDataSet3D.GetData(Index: longint): TVector3D;
  1563. begin
  1564.   with TVector3D(Ptr(Longint(FData)+(Index*SizeOf(TVector3D)))^) do
  1565.   begin
  1566.     Result.x := x;
  1567.     Result.y := y;
  1568.     Result.z := z;
  1569.   end;
  1570. end;
  1571.  
  1572. procedure TDataSet3D.SetCount(AValue: longint);
  1573. begin
  1574.   if AValue <> FCount then
  1575.   begin
  1576.     FCount := AValue;
  1577.     ReAllocMem(FData,AValue*SizeOf(TVector3D));
  1578.   end;
  1579. end;
  1580.  
  1581. constructor TDataSet3D.Create(ACount: longint);
  1582. begin
  1583.   inherited Create;
  1584.   FCount := ACount;
  1585.   GetMem(FData,ACount*SizeOf(TVector3D));
  1586. end;
  1587.  
  1588. destructor TDataSet3D.Destroy;
  1589. begin
  1590.   FreeMem(FData,FCount*SizeOf(TVector3D));
  1591.   inherited Destroy;
  1592. end;
  1593.  
  1594. end.
  1595.